package com.laundry.user.ui.home

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.laundry.user.model.LaundryService
import com.laundry.user.network.NetworkResult
import com.laundry.user.repository.LaundryRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.*
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.junit.MockitoJUnitRunner
import org.junit.Assert.*

@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class HomeViewModelTest {
    
    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()
    
    private val testDispatcher = UnconfinedTestDispatcher()
    
    @Mock
    private lateinit var repository: LaundryRepository
    
    private lateinit var viewModel: HomeViewModel
    
    @Before
    fun setup() {
        Dispatchers.setMain(testDispatcher)
        viewModel = HomeViewModel(repository)
    }
    
    @After
    fun tearDown() {
        Dispatchers.resetMain()
    }
    
    @Test
    fun `loadServices success should update services and hide loading`() = runTest {
        // Given
        val mockServices = listOf(
            LaundryService(
                id = 1,
                name = "普通洗衣",
                description = "日常衣物清洗",
                price = 15.0,
                imageUrl = "",
                category = "洗衣"
            ),
            LaundryService(
                id = 2,
                name = "干洗服务",
                description = "高档衣物干洗",
                price = 35.0,
                imageUrl = "",
                category = "干洗"
            )
        )
        
        `when`(repository.getServices())
            .thenReturn(flowOf(NetworkResult.Success(mockServices)))
        
        // When
        viewModel.loadServices()
        
        // Then
        assertEquals(mockServices, viewModel.services.value)
        assertEquals(false, viewModel.isLoading.value)
    }
    
    @Test
    fun `loadServices error should show error message and hide loading`() = runTest {
        // Given
        val errorMessage = "网络错误"
        `when`(repository.getServices())
            .thenReturn(flowOf(NetworkResult.Error(errorMessage)))
        
        // When
        viewModel.loadServices()
        
        // Then
        assertEquals(errorMessage, viewModel.errorMessage.value)
        assertEquals(false, viewModel.isLoading.value)
        assertTrue(viewModel.services.value?.isEmpty() ?: true)
    }
    
    @Test
    fun `loadServices loading should show loading state`() = runTest {
        // Given
        `when`(repository.getServices())
            .thenReturn(flowOf(NetworkResult.Loading()))
        
        // When
        viewModel.loadServices()
        
        // Then
        assertEquals(true, viewModel.isLoading.value)
    }
}
